
// strategies return false when ineffective.
// strategies return true when successfully performed.

// Solver procedure, takes a handler function as input.
// The technique used in the handler function are expected to be able to produce valid solution grid.
// As such this function attempts to make the operation atomic, meaning if solving fails user's grid is unchanged. 
function Solver(func)
{
	var SolutionGrid = new SudokuGrid(SudokuUI.clueGrid);
	SolutionGrid.populateNotations();

	if (SolutionGrid.dataCount < 15) // Minimum number of clues for a unique solution grid currently is 17. 
	{
		alert('Insufficent clues provided.');
		return;
	}

	var origCount = SolutionGrid.candidateCount();

	SudokuUI.log.clear();

	var origCount = SolutionGrid.candidateCount();

	var start = new Date();

	SolutionGrid = func(SolutionGrid);

	var finish = new Date();
	var duration = finish.getTime() - start.getTime();

	SudokuUI.log.print(' ');
	SudokuUI.log.print('Solver runtime: '+ duration +'ms');
	SudokuUI.log.display();

	var newCount = SolutionGrid.candidateCount();
	console.log(origCount + '->' + newCount);

	SudokuUI.progressGrid = new SudokuGrid(SolutionGrid); 

	SudokuUI.controller.setNotationSrc('notations');
	//SudokuUI.controller.refreshDisplay(); // called automatically by the previous function

	if (newCount !== 81)
	{
		if (newCount > origCount || newCount < 81)
			alert('Script error: One or more of the solving functions generated incorrect result.');
		else
		{
			if(confirm('Unable to solve the puzzle using implemented human techniques.\nDo you wish to solve the puzzle by remodeling it as an Exact Cover problem?'))
				Solver(ExactCoverHandler);
		}
	}
}

// Solver precedure for one single logical technique. 
// Since a single technique is rarely a full-fledged solver, this precedure does not attempt to be atomic. 
// In addition, it does not attempt to check if the resulting grid is valid. 
function SolverIndividualTechnique(func)
{
	var SolutionGrid = new SudokuGrid(SudokuUI.progressGrid);

	try
	{
		SolutionGrid[func]();
	}
	catch(e)
	{
		alert('Technique resulted in invalid grid.');
		return;
	}
	SudokuUI.progressGrid = new SudokuGrid(SolutionGrid); 

	SudokuUI.controller.refreshDisplay();
	SudokuUI.controller.setNotationSrc('notations');
}

// This solver handler loop through logical solving techniques
function LogicalHandler(SolutionGrid)
{
	try
	{
		SolutionGrid.solveLoop(LogicalSolveStep, SudokuUI.log.print);
	}
	catch(e)
	{
		alert('An error occured during solving. \n\n' + e.name + ': ' + e.message);
		return;
	}
	return SolutionGrid;
}

// This solver handler uses nishio technique
function NishioHandler(SolutionGrid)
{
	SolutionGrid.strategyNishio();
	return SolutionGrid;
}

// This solver handler uses through Exact Cover technique
function ExactCoverHandler(SolutionGrid)
{
	SudokuUI.log.print('Exact Cover');

	var DLXGrid = new SudokuDLX(SolutionGrid);
	var result = DLXGrid.solve();

	result.populateNotations();
	return result;
}
